package org.db.createsql;


import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.Date;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.db.comments.Key;
import org.db.comments.NotNull;
import org.db.comments.NumException;
import org.db.comments.Table;
import org.db.comments.notRecord;
import org.db.createdao.BaseDao;
import org.db.createdao.DaoPo;
import org.db.createdao.DatabaseUser;
import org.transmit.StartUtil;
import org.transmit.ThreadDao;


/**
 * 
 * <p>Title: AbstrDaoMssql   </p>
 * <p>Description:mssql实现类</p>
 * <p>Copyright: Copyright (c) 2012</p>
 * <p>Company: prd</p>
 * <p>Create Date/Time: 2014年8月13日 下午9:02:08<p>
 * @author porridge
 * @version 1.0
 * @url www.prdblog.com
 *
 */
public class AbstrDaoMssql implements RealizeDaoInter{
	
	DaoPo dao=ThreadDao.getDaoPo();
	
	public Connection getConnection() throws SQLException {
		return dao.getCon();
	}
	/**
	 * 保存实体类
	 * @param cl
	 * @return
	 * @throws Exception 
	 */
	public String save(Object cl) throws Exception{
		String sql="insert into ";
		String id=null;
		List<String> ls=null;// 用来存放
		if(cl==null)
			throw new NumException("传入对象不能为空");//抛出异常
		Field[] fiels=cl.getClass().getDeclaredFields();//获得反射对象集合
		sql+=findTablename(cl.getClass());//获得表名
		String name ="";//记录字段名
		String value ="";//记录值名称
		boolean bl=false;//记录主键是否为空
		boolean notnull=false;//记录必填是否为空
		for(Field fl:fiels){//循环组装
			fl.setAccessible(true);//开启支私有变量的访问权限
			Object tobj=fl.get(cl);
			if(ls==null)
				ls=new ArrayList<String>();
			if(fl.isAnnotationPresent(Key.class)){//如果主键为空则填充Uuid
				name+=fl.getName()+",";
				if(tobj!=null && tobj.toString().trim().length()>0)
					id=tobj.toString().trim();
				else
					id=StartUtil.getUUID();
				value+="?,";
				ls.add(id);
				bl=true;
			}else{
				if(tobj!=null){
					if(!fl.isAnnotationPresent(notRecord.class)){
						name+=fl.getName()+",";
						value+="?,";
						ls.add(fl.get(cl).toString());
					}
				}else{
					if(fl.isAnnotationPresent(NotNull.class)){//判断是否有非空验证项目的存在
							notnull=true;
					}
				}
			}
		}
		if(notnull){
			throw new NumException("必填属性不能为空");
		}
		if(bl && ls!=null){
			if(name.length()>0)
				name=name.substring(0,name.length()-1);
			if(value.length()>0)
				value=value.substring(0,value.length()-1);
			//组装sql完成开始数据库操作
			sql+="("+name+") values("+value+")";
			try {
				dao.setPs(dao.getCon().prepareStatement(sql));
				for(int i=0;i<ls.size();i++){//为他的值一个一个填充
					dao.getPs().setString(i+1,ls.get(i));
				}
				BaseDao.dao.showsql(sql);
				if(dao.getPs().executeUpdate()==0)
					id=null;
				BaseDao.dao.showsql("save data result:"+(id==null?"error":"  success saveid="+id));
			} catch (SQLException e) {
				id=null;
				BaseDao.dao.showsql("inert into  error:"+sql);
				e.printStackTrace();
			}
		}else{
			id=null;
			throw new NumException("未找到类主键 主键不能为空");
		}
		return id;
	}
	/**
	 * 更新实体类
	 * @param obj
	 * @throws Exception 
	 */
	public int update(Object obj) throws Exception{
		int sum=0;
		List<String> ls=null;
		String sql="update ";
		boolean notnull=false;//记录必填是否为空
		if(obj==null)
			throw new NumException("传入对象不能为空");//抛出异常
		
		Field[] fiels=obj.getClass().getDeclaredFields();//获得反射对象集合
		
		sql+=findTablename(obj.getClass())+" set ";//获得表名
		String wh ="";//记录字段名
		String k="";
		String key="";
		boolean bl=false;//记录主键是否为空
		for(Field fl:fiels){//循环组装
			fl.setAccessible(true);//开启支私有变量的访问权限
			Object tobj=fl.get(obj);
			if(ls==null)
				ls=new ArrayList<String>();
			if(tobj!=null){
				if(fl.isAnnotationPresent(Key.class)){//判断是否存在主键
					bl=true;
					k=" where "+fl.getName()+"=? ";
					key=tobj.toString();
				}else{
					if(!fl.isAnnotationPresent(notRecord.class)){
						wh+=fl.getName()+"=?,";
						ls.add(tobj.toString());
					}
				}
			}else{
				if(fl.isAnnotationPresent(NotNull.class)){//判断是否有非空验证项目的存在
					notnull=true;
				}
			}
		}
		if(notnull){
			throw new NumException("必填属性不能为空");
		}
		if(!bl)
			throw new NumException("未找到类主键 主键不能为空");
		if(wh.length()>0)
			wh=wh.substring(0,wh.length()-1);
		if(k.length()>0)
			k=k.substring(0,k.length()-1);
		sql+=wh+k;
		BaseDao.dao.showsql(sql);
		//开始处理sql语句
		try {
			dao.setPs(dao.getCon().prepareStatement(sql));
			for(int i=0;i<ls.size();i++){
				dao.getPs().setString(i+1,ls.get(i));
			}
			dao.getPs().setString(ls.size()+1,key);
			sum=dao.getPs().executeUpdate();
			BaseDao.dao.showsql("update dada influence row:"+sum);
		} catch (SQLException e) {
			BaseDao.dao.showsql("更新数据失败 error:"+sql);
			e.printStackTrace();
		}finally{
			return sum;
		}
	}
	/**
	 * 删除某个对象  
	 * @param cl
	 * @return
	 * @throws Exception 
	 */
	public int dele(Object cl) throws Exception{
		int sum=-1;
		if(cl==null)
			throw new NumException("传入对象不能为空");//抛出异常
		Field[] fiels=cl.getClass().getDeclaredFields();//获得反射对象集合
		String id="";
		for(Field fl:fiels){//循环组装
			if(fl.isAnnotationPresent(Key.class)){//判断是否存在主键
				fl.setAccessible(true);//开启支私有变量的访问权限
				id=" where "+fl.getName()+"='"+fl.get(cl).toString()+"'";
				break;
			}
		}
		if(id=="")
			throw new NumException("未查询到主键或者主键为空");
		id="delete from "+findTablename(cl.getClass())+id;
		BaseDao.dao.showsql(id);
		try {
			dao.setPs(dao.getCon().prepareStatement(id));
			sum=dao.getPs().executeUpdate();
			BaseDao.dao.showsql("delete dada influence row:"+sum);
		} catch (SQLException e) {
			BaseDao.dao.showsql("删除对象出现错误 error:"+id);
			e.printStackTrace();
		}finally{
			return sum;
		}
	}
	/**
	 * 根据条件删除
	 * @param cl  对象
	 * @param where  条件
	 * @return
	 * @throws Exception 
	 */
	public int dele(Class<?> table,String where) throws Exception{
		int sum=-1;
		if(where==null)
			throw new NumException("未传入删除条件");
		if(where=="" || where.length()==0)
			throw new NumException("未传入删除条件");
		
		String sql="";
		sql="delete from "+findTablename(table)+" where "+where;
		BaseDao.dao.showsql(sql);
		try {
			dao.setPs(dao.getCon().prepareStatement(sql));
			sum=dao.getPs().executeUpdate();
			BaseDao.dao.showsql("delete dada influence row:"+sum);
		} catch (SQLException e) {
			BaseDao.dao.showsql("删除对象出现错误 error:"+sql);
			e.printStackTrace();
		}finally{
			return sum;
		}
	}
	/**
	 * 删除某个对象
	 * 传入过id
	 * @throws Exception 
	 */
	public int deletable(Class<?> table,String where)throws Exception{
		if(where==null || where=="")
			return -1;
		String sql="delete from "+findTablename(table)+" where "+where;
		BaseDao.dao.showsql(sql);
		dao.setPs(dao.getCon().prepareStatement(sql));
		int sum=dao.getPs().executeUpdate();
		BaseDao.dao.showsql("delete dada influence row:"+sum);
		return sum;
	};
	/**
	 * 根据主键查询实体类
	 * @param cls 类型
	 * @param id  主键名称
	 * @return 
	 * @return
	 * @throws Exception 
	 * @throws SQLException 
	 */
	public <T> T find(Class<?> cls,String id) throws Exception{
		Object obj=cls.newInstance();
		String sql="";
		if(id==null || id=="")
			throw new NumException("请传入查询条件");
		
		String idname="";//存放主键名称
		boolean bl=true;//用来判断是否有主键
		Field[] files=obj.getClass().getDeclaredFields();
		for(Field fl:files){
			fl.setAccessible(true);
			if(fl.isAnnotationPresent(notRecord.class))
				continue;
			if(fl.isAnnotationPresent(Key.class)){
				bl=false;
				idname=fl.getName();
			}
			sql+=fl.getName()+",";
		}
		if(bl)
			throw new NumException("实体类没有主键");
		sql=sql.substring(0,sql.length()-1);
		try {
			String tempsql="select "+sql+" from  "+findTablename(cls)+" where "+idname+" =?";
			BaseDao.dao.showsql(tempsql);//打印sql
			dao.setPs(dao.getCon().prepareStatement(tempsql));
			dao.getPs().setString(1,id);
			dao.setRs(dao.getPs().executeQuery());
			if(dao.getRs().next()){
				for(Field fl:files){
					fl.setAccessible(true);
					if(fl.isAnnotationPresent(notRecord.class))
						continue;
					if(String.class==fl.getType())
						fl.set(obj,dao.getRs().getString(fl.getName()));
					if("int".equals(fl.getType().toString())){
						fl.set(obj,dao.getRs().getInt(fl.getName()));
					}
					if(Date.class==fl.getType())
						fl.set(obj,dao.getRs().getDate(fl.getName()));
				}
			}
		}catch (SQLException e){
			BaseDao.dao.showsql("查询单个实体类出现错误");
			e.printStackTrace();
		}finally{
			return (T)obj;
		}
	}
	
	/**
	 * 查询实体类集合
	 * @param table 实体
	 * @param row  列名
	 * @return
	 * @throws Exception 
	 */
	public <T> List<T> getList(Class<?> table,String row) throws Exception{
		return getList(table,row,null,null,null,0,200);
	}
	/**
	 * 查询实体类集合
	 * @param table 实体
	 * @param row 列名
	 * @param min 起始行
	 * @param max 终止行
	 * @return
	 * @throws Exception 
	 */
	public <T> List<T> getList(Class<?> table,String row,int min,int max) throws Exception{
		return getList(table,row,null,null,null,min,max);
	}
	/**
	 * 查询实体类集合
	 * @param table 实体
	 * @param row 列名
	 * @param where 条件
	 * @return
	 * @throws Exception 
	 */
	public <T> List<T> getList(Class<?> table,String row,String where) throws Exception{
		return getList(table,row,where,null,null,0,200);
	}
	/**
	 * 查询实体类集合
	 * @param table 实体
	 * @param row 列名
	 * @param where 条件
	 * @param or 排序 字段
	 * @param orcls 排序类型 如desc asc
	 * @return
	 * @throws Exception 
	 */
	public <T> List<T> getList(Class<?> table,String row,String where,String or,String orcls) throws Exception{
		return getList(table,row,where,or,orcls,0,200);//默认的二百行数据
	}
	/**
	 * 查询实体类集合
	 * @param <T>
	 * @param table 实体
	 * @param row  列名
	 * @param where  条件
	 * @param or  排序字段
	 * @param orcls 排序类型 如desc asc
	 * @param min  开始行数
	 * @param max 结束行数
	 * @return
	 * @throws Exception 
	 */
	public <T> List<T> getList(Class<?> table,String row,String where,String or,String orcls,int min,int max) throws Exception{
		Object obj=table.newInstance();
		List<T> ls=new ArrayList<T>();//存放集合
		String sql="";
		String idname="";//存放主键名称
				
		boolean bl=true;//用来判断是否有主键
		String[] rowrs=null;
		Map<String,String> map=new HashMap<String,String>();//用来存放字段名称
		if(row!=null && !"*".equals(row.trim()))//如果不等于 空并且不是*号则对比读出
			rowrs=row.split(",");
		Field[] files=obj.getClass().getDeclaredFields();
		String tn="";//临时存放列名
		//进行列名组合  start
		for(Field fl:files){
			fl.setAccessible(true);
			if(fl.isAnnotationPresent(notRecord.class))
				continue;
			if(fl.isAnnotationPresent(Key.class)){
				bl=false;
				idname=fl.getName();
			}
			tn=fl.getName();
			if(rowrs==null){
				sql+=tn+",";
				map.put(tn,fl.getType().toString());
			}else{
				for(String r:rowrs){
					if(r.trim().equals(tn.trim())){
						sql+=tn+",";
						map.put(tn,fl.getType().toString());
					}
				}
			}
		}
		//进行列名组合  end
		or=idname;
		if(bl)
			throw new NumException("实体类没有主键");
		try {
			if(or!=null){
				if(map.get(or.trim())!=null && orcls!=null){//增加排序
					if("asc".equals(orcls.trim()) || "desc".equals(orcls.trim())){
						sql+="ROW_NUMBER() over (order by "+or+" "+orcls.trim()+" ) as RowNumber";
					}
				}else
					sql+="ROW_NUMBER() over (order by "+or+" desc ) as RowNumber";
			}
			String twh="";
			if(where!=null){//加条件
				if(where.trim().length()!=0)
					twh=" where "+where;
			}
			sql="select * from ( select "+sql+" from "+findTablename(table)+" "+twh+" ) t where RowNumber between "+min+" and "+max;
			BaseDao.dao.showsql(sql);//打印sql
			
			dao.setPs(dao.getCon().prepareStatement(sql));
			dao.setRs(dao.getPs().executeQuery());
			while(dao.getRs().next()){
				obj=table.newInstance();
				for(Field fl:files){
					fl.setAccessible(true);
					tn=fl.getName();
					if(map.get(tn)!=null){
						if(String.class==fl.getType())
							fl.set(obj,dao.getRs().getString(tn));
						if("int".equals(fl.getType().toString())){
							fl.set(obj,dao.getRs().getInt(tn));
						}
						if(Date.class==fl.getType())
							fl.set(obj,dao.getRs().getDate(tn));
					}
				}
				if(obj!=null)
					ls.add((T) obj);
			}
			BaseDao.dao.showsql("find data size:"+ls.size());
		}catch (SQLException e){
			BaseDao.dao.showsql("查询实体类出现错误");
			e.printStackTrace();
		}finally{
			return ls;
		}
	}
	/**
	 * 查询某个实体类一直有多少行数据
	 * @param table 实体
	 * @return
	 * @throws Exception 
	 */
	public int getCount(Class<?> table) throws Exception{
		return getCount(table,"1=1");
	}
	/**
	 * 执行自定义sql语句 查询列表
	 * @throws SQLException 
	 */
	public ResultSet findQuery(String sql) throws SQLException {
		dao.setPs(dao.getCon().prepareStatement(sql));
		return dao.getPs().executeQuery();
	}
	/**
	 * 执行删除或修改的语句
	 * @throws SQLException 
	 */
	public int updateordelete(String sql) throws SQLException {
		dao.setPs(dao.getCon().prepareStatement(sql));
		return dao.getPs().executeUpdate(sql);
	}
	
	/**
	 * 查询某张表的数据
	 */
	public int getCount(String table,String where) throws NumException, SQLException,
			InstantiationException, IllegalAccessException {
		String sql="";
		sql="select COUNT(1) from "+table+" where "+where;
		BaseDao.dao.showsql(sql);
		dao.setPs(dao.getCon().prepareStatement(sql));
		dao.setRs(dao.getPs().executeQuery());
		dao.getRs().next();
		return dao.getRs().getInt(1);
	}
	/**
	 * 查询单张表
	 *  id 条件 
	 * @throws SQLException 
	 */
	public String findtable(Class<?> table,String id) throws NumException,
			InstantiationException, IllegalAccessException, SQLException {
		JSONObject json=new JSONObject(); 
		String sql="";
		if(id==null || id=="")
			return "请传入查询条件";
		
		String idname="";//存放主键名称
		boolean bl=true;//用来判断是否有主键
		Field[] files=table.getDeclaredFields();
		List<String> filename=new ArrayList<String>();
		for(Field fl:files){
			fl.setAccessible(true);
			if(fl.isAnnotationPresent(notRecord.class))
				continue;
			if(fl.isAnnotationPresent(Key.class)){
				bl=false;
				idname=fl.getName();
			}
			filename.add(fl.getName());
			sql+=fl.getName()+",";
		}
		if(bl)
			return "实体类没有主键";
		
		sql=sql.substring(0,sql.length()-1);
		try {
			sql="select "+sql+" from "+findTablename(table)+" where "+idname+" =?";
			BaseDao.dao.showsql(sql);//打印sql
			dao.setPs(dao.getCon().prepareStatement(sql));
			dao.getPs().setString(1,id);
			dao.setRs(dao.getPs().executeQuery());
			if(dao.getRs().next()){
				for(String l:filename){
					json.put(l,dao.getRs().getString(l));
				}
			}
		}catch (SQLException e){
			return "error";
		}finally{
			return json.toString();
		}
	}
	/**
	 * 查询jqgrid
	 * @throws Exception 
	 */
	public String getListJqgrid(Class<?> table, String row, String where,
			String or, String orcls, int min, int max)throws Exception {
		return getListJqgrid(findTablename(table),row,where,or,orcls,min,max);
	}
	/**
	 * 返回grid字符串格式
	 * @throws SQLException 
	 */
	public String getListJqgrid(String tablename, String row, String where,
			String or, String orcls, int min, int max)throws InstantiationException, IllegalAccessException, NumException, SQLException {
		//目标页数   每页数量
		String json="";
		String[] rows=row.split(",");
		int n1=min*max;
		int n2=n1-max;
		String sql="select * from ( select "+row+",ROW_NUMBER() over (order by "+or+" "+orcls+" ) as RowNumber from "+tablename+"  where "+where+" ) t where RowNumber between "+n2+" and "+n1;
		int tablemax=getCount(tablename,where);//得到总条数
		
		int pagetal=tablemax/max;
		if(tablemax%max!=0)
			pagetal++;
		
		BaseDao.dao.showsql(sql);
		dao.setPs(dao.getCon().prepareStatement(sql));
		dao.setRs(dao.getPs().executeQuery());
		JSONObject json1=new JSONObject();
		json1.put("page",min);
		json1.put("total",pagetal);
		json1.put("records",tablemax);
		JSONArray jary2=new JSONArray();
		JSONArray jary3=new JSONArray();
		JSONObject json2=new JSONObject();
		int rowmax=rows.length;
		int i;
		Object obj;
		while(dao.getRs().next()){
			json2=new JSONObject();
			jary3=new JSONArray();
			json2.put("id",dao.getRs().getString(rows[0]).trim());
			for(i=1;i<rowmax;i++){
				obj=dao.getRs().getString(rows[i]);
				if(obj!=null)
					jary3.add(obj.toString());
				else
					jary3.add("");
			}
			json2.put("cell",jary3);
			jary2.add(json2);
		}
		json1.put("rows",jary2);
		return json1.toString();
	}
	@Override
	public int getCount(Class<?> table, String where) throws Exception {
		String sql="select COUNT(1) from "+findTablename(table)+" where "+where;
		BaseDao.dao.showsql(sql);
		dao.setPs(dao.getCon().prepareStatement(sql));
		dao.setRs(dao.getPs().executeQuery());
		dao.getRs().next();
		int sum=dao.getRs().getInt(1);
		BaseDao.dao.showsql("count number:"+sum);
		return sum;
	}
	
	@Override
	public String tableMax(Class<?> table, String file)throws Exception {
		return tableMax(table,file,"1=1");
	}
	@Override
	public String tableMax(Class<?> table, String file, String where)throws Exception {
		String sql="select max("+file+") from "+findTablename(table)+" where "+where;
		BaseDao.dao.showsql(sql);
		dao.setPs(dao.getCon().prepareStatement(sql));
		dao.setRs(dao.getPs().executeQuery());
		dao.getRs().next();
		return dao.getRs().getString(1);
	}
	/**
	 * 传入对象返回表名
	 */
	@Override
	public String findTablename(Class<?> table) throws Exception{
		Object obj=table.newInstance();
		boolean bl=obj.getClass().isAnnotationPresent(Table.class);
		if(!bl)
			throw new NumException("请传入实体类");
		Table tab=obj.getClass().getAnnotation(Table.class);//获得表主键
		return tab.name();
	}
}